home *** CD-ROM | disk | FTP | other *** search
- /* module: window.c
- * programmer: Ray L. McVay
- * started: 1 Aug 84
- * version: 1.2, 23 Aug 84
- * version: 1.3, 14 Jun 86 as modified by Larry A. Thiel
- * (I hope this version # doesn't conflict)
- *
- * A simple window package based on the article and programs
- * by Edward Mitchell in the Jan 84 Dr. Dobb's Journal. This
- * implementation uses dynamically allocated buffers for the
- * window control blocks and screen save buffers.
- *
- * An assembly language support library called VLIB is used to
- * interface the DeSmet C compiler with the IBM ROM BIOS video
- * routines. VLIB will undoubtedly have to be rewritten if the
- * window package is to be used with other compilers.
- *
- * History -
- *
- * 1.1 - Added style member to wcb structure, clr_window() and
- * use of wn->cx for horizontal scrolling in write_text().
- *
- * 1.2 - Added oldx, oldy members to wcb structure and use them
- * in draw_window() and remove_window().
- *
- * 1.3 - Added wpage member to wcb structure, functions pputch(),
- * pgetch(), and pdraw_row() to window.c, and get_page() to vlib.a
- * to permit windows on video pages other than 0.
- * Added win_write() to provide better treatment of the window as
- * a glass tty. Requires care if old method used for horizontal
- * scrolling.
- * Added ticker() and wticker() to window.c, get_curtyp(), kbd_ci(),
- * and kbd_csts for ticker tape input with editing. ticker() may be
- * used without a window. kbd_csts() is not used here but is
- * available for use.
- */
-
- #include <stdio.h>
- #include <window.h>
-
- #define HOME 0x8A /* HOME key */
- #define CURLF 0x8B /* <- */
- #define ENDKEY 0x8C /* END key */
- #define CURRT 0x9B /* -> */
- #define INSERT 0x9D /* Ins */
- #define DELETE 0x9E /* Del */
-
- /*********************
- ** desmet functions */
-
- int isprint();
-
- /*********************
- ** vlib1 functions */
-
- int get_page(), get_curtyp(), getxy(), vgetc();
- void gotoxy(), set_curtyp(), scrlup(), scrldn(), vputc(), vputca();
-
- /************************************************************************
- * putch(), write a character and attribute to a specific XY location on *
- * the screen. The attribute is the high byte of the character. *
- ************************************************************************/
-
- void pputch(x, y, c)
- int x, y, c;
- {
- gotoxy(x, y, 0);
- vputca(c, 0, 1);
- }
-
-
- /*************************************************
- * pputch(), same as putch except uses page arg **
- *************************************************/
-
- void putch(x, y, c, page)
- int x, y, c;
- {
- gotoxy(x, y, page);
- vputca(c, page, 1);
- }
-
-
- /************************************************************************
- * getch(), return the character and attribute at screen XY *
- ************************************************************************/
-
- int getch(x, y)
- int x, y;
- {
- gotoxy(x, y, 0);
- return(vgetc(0));
- }
-
-
- /*************************************************
- * pgetch(), same as getch except uses page arg **
- *************************************************/
-
- int pgetch(x, y, page)
- int x, y;
- {
- gotoxy(x, y, page);
- return(vgetc(page));
- }
-
-
- /************************************************************************
- * draw_row(), output a row of one character/attribute at XY *
- ************************************************************************/
-
- void draw_row(x, y, count, c)
- int x, y, count,c;
- {
- gotoxy(x, y, 0);
- vputca(c, 0, count);
- }
-
-
- /********************************************************
- * pdraw_row(), same as draw_row except uses page arg *
- ********************************************************/
-
- void pdraw_row(x, y, count, c, page)
- int x, y, count,c;
- {
- gotoxy(x, y, page);
- vputca(c, page, count);
- }
-
-
- /************************************************************************
- * draw_window(), open a window of given size with upper left corner at *
- * XY. Allocates buffers for the window control block and *
- * screen save buffers. Copies overwritten screen to the *
- * buffer. Draws the blank window. Returns the address of *
- * the window control block or NULL if no buffer space. *
- ************************************************************************/
-
- WINDOWPTR draw_window(x, y, width, height, attrib)
- int x, y, width, height, attrib;
- {
- WINDOWPTR wn;
- int tx, ty,
- xend, yend;
- int *tptr;
- char *calloc();
-
- if ((wn = (WINDOWPTR)calloc(1, sizeof(WINDOW))) == NULL)
- return(NULL);
- else if ((wn->scrnsave = (int *)calloc((width+2) * (height+2), sizeof(int))) == NULL)
- {
- free(wn);
- return(NULL);
- }
- else
- {
- /* store parameters in window control block */
-
- wn->wpage = get_page(); /* what video page are we on */
- wn->ulx = x;
- wn->uly = y;
- wn->xsize = width;
- wn->ysize = height;
- wn->cx = 1;
- wn->cy = 1;
- wn->style = attrib;
- attrib <<= 8; /* will make things below go quicker */
- tx = getxy(wn->wpage);
- wn->oldx = tx & 255;
- wn->oldy = tx >> 8;
-
- /* Copy existing text where the window will be placed */
- /* to the scrnsave buffer. Obviously, a less portable */
- /* routine could be much faster. */
-
- tptr = wn->scrnsave;
- xend = x + width + 2;
- yend = y + height + 2;
-
- for (ty = y; ty < yend; ty++)
- {
- for (tx = x; tx < xend; tx++)
- *tptr++ = pgetch(tx, ty, wn->wpage);
- }
-
- /* draw the window border and clear the text area */
-
- pputch(x, y, 0xda + attrib, wn->wpage); /* ul corner */
- pdraw_row(x + 1, y, width, 0xc4 + attrib, wn->wpage); /* horiz bar */
- pputch(x + width + 1, y, 0xbf + attrib, wn->wpage); /* ur corner */
-
- yend = y + height;
-
- for (ty = y+1; ty <= yend; ty++)
- {
- pputch(x, ty, 0xb3 + attrib, wn->wpage); /* draw the sides */
- pputch(x+width+1, ty, 0xb3 + attrib, wn->wpage);
- }
-
- pputch(x, y + height + 1, 0xc0 + attrib, wn->wpage); /* ll corner */
- pdraw_row(x + 1, y + height + 1, width, 0xc4 + attrib, wn->wpage); /* horiz bar */
- pputch(x + width + 1, y + height + 1, 0xd9 + attrib, wn->wpage); /* lr corner */
-
- clr_window(wn);
-
- return(wn);
- }
- }
-
-
- /************************************************************************
- * remove_window(), erase the window at the window control block. *
- * Must be the "top" window if overlapping windows are *
- * used. "Tiled" windows could be removed randomly. *
- ************************************************************************/
-
- void remove_window(wn)
- WINDOWPTR wn;
- {
- int tx, ty,
- xend, yend;
- int *tptr;
-
- /* just repaint the saved text at the appropriate location */
-
- tptr = wn->scrnsave;
- xend = wn->ulx + wn->xsize + 2;
- yend = wn->uly + wn->ysize + 2;
-
- for (ty = wn->uly; ty < yend; ty++)
- {
- for (tx = wn->ulx; tx < xend; tx++)
- pputch(tx, ty, *tptr++, wn->wpage);
- }
-
- /* put cursor back where it was before this rude interruption */
-
- gotoxy(wn->oldx, wn->oldy, wn->wpage);
-
- /* then release the dynamic storage used */
-
- free(wn->scrnsave);
- free(wn);
- }
-
-
- /************************************************************************
- * write_text(), print a string inside a window using cx, cy in WCB *
- ************************************************************************/
-
- void write_text(wn, string)
- WINDOWPTR wn;
- char *string;
- {
- int tx, ty, xend;
-
- /* first check to see if we're at the bottom of the window */
- /* if we are then scroll the contents of the window up */
-
- if (wn->cy > wn->ysize)
- {
- delete_row(wn, 1);
- --wn->cy;
- }
-
- /* Print as much of the string as will fit in the window. *
- * cx is used for relative left margin. If cx is negative then *
- * the first cx characters will be removed from the string to *
- * allow horizontal scrolling in the window. *
- * NOTE: This obviously simple-minded technique is usable for *
- * displaying predetermined messages but a more general *
- * console output intercept should be used for Star-like *
- * environments. */
-
- if (wn->cx > 0)
- tx = wn->ulx + wn->cx;
- else
- {
- if (-wn->cx < strlen(string))
- string -= wn->cx;
- else
- *string = '\0';
- tx = wn->ulx + 1;
- }
- xend = wn->ulx + wn->xsize + 1;
- ty = wn->uly + wn->cy;
- while ((tx < xend) && *string)
- {
- gotoxy(tx++, ty, wn->wpage);
- vputc(*string++, wn->wpage, 1);
- }
- ++wn->cy; /* move the internal cursor to the next line */
- }
-
-
- /*****************************************************************
- ** Another function to write text to a window. This one uses the**
- ** window like a glass teletype and processes certain control **
- ** characters. As a result, it will not do the right thing if **
- ** you send it '\n' or '\r' chars after changing wn->cx to cause**
- ** horizontal scrolling. Tabs are NOT expanded. */
-
- void win_text(wn,cptr)
-
- WINDOWPTR wn;
- char *cptr;
- {
- /* draw_window() does not position cursor AND **
- ** user may have moved it anyway, so start by **
- ** putting it where it belongs. */
-
- gotoxy ( wn->ulx + wn->cx, wn->uly + wn->cy, wn->wpage );
-
- while ( *cptr )
- {
- switch ( *cptr )
- {
- case '\n': wn->cy++;
- if ( wn->cy > wn->ysize ) /* if past bottom of */
- { delete_row ( wn, 1 ); /* window, scroll up */
- --wn->cy;
- } /* pass thru to '\r' */
- case '\r': wn->cx = 1;
- break;
- case 7: co (*cptr); /* just ring bell */
- break;
- case '\t': *cptr = ' '; /* replace tab & pass on*/
- default: if ( wn->cx <= wn->xsize )
- vputc ( *cptr, wn->wpage, 1 );
- wn->cx++;
- }
- gotoxy ( wn->ulx + wn->cx, wn->uly + wn->cy, wn->wpage );
- cptr++;
- }
- }
-
- /************************************************************************
- * insert_row(), insert a row of blanks by scrolling the lower portion *
- * of a window down *
- ************************************************************************/
-
- void insert_row(wn, row)
- WINDOWPTR wn;
- int row;
- {
- int scrlwn[4];
-
- /* calculate corners of the scrolling window */
-
- scrlwn[0] = wn->ulx + 1; /* ulx */
- scrlwn[1] = wn->uly + row; /* uly */
- scrlwn[2] = wn->ulx + wn->xsize; /* lrx */
- scrlwn[3] = wn->uly + wn->ysize; /* lry */
-
- scrldn(scrlwn, 1, wn->style);
- }
-
-
- /************************************************************************
- * delete_row(), delete a row by scrolling the lower portion of a window *
- * up and inserting a row of blanks at the bottom row *
- ************************************************************************/
-
- void delete_row(wn, row)
- WINDOWPTR wn;
- int row;
- {
- int scrlwn[4];
-
- /* calculate corners of the scrolling window */
-
- scrlwn[0] = wn->ulx + 1; /* ulx */
- scrlwn[1] = wn->uly + row; /* uly */
- scrlwn[2] = wn->ulx + wn->xsize; /* lrx */
- scrlwn[3] = wn->uly + wn->ysize; /* lry */
-
- scrlup(scrlwn, 1, wn->style);
- }
-
-
- /************************************************************************
- * clr_window(), clear the "active" part of a window and "home" internal *
- * text cursor *
- ************************************************************************/
-
- void clr_window(wn)
- WINDOWPTR wn;
- {
- int scrlwn[4];
-
- /* calculate corners of the scrolling window */
-
- scrlwn[0] = wn->ulx + 1; /* ulx */
- scrlwn[1] = wn->uly + 1; /* uly */
- scrlwn[2] = wn->ulx + wn->xsize; /* lrx */
- scrlwn[3] = wn->uly + wn->ysize; /* lry */
-
- scrlup(scrlwn, 0, wn->style);
- wn->cx = 1;
- wn->cy = 1;
- }
-
- /*********************************************************************
- ** Operator edit of null terminated string in buffer at ptr. Buffer **
- ** size must be > max bytes and function will allow result to be up **
- ** to max bytes in length. Function may be called with an empty **
- ** string for entry of all new data. Function will use width chars **
- ** at row, col of video page page to display a ticker tape of the **
- ** working string. Function returns the length of the result. */
-
- int ticker(row,col,ptr,max,width,page)
-
- int row, col, max, width;
- char *ptr;
- {
- int i, j, toffset, tcur, spos, count, key, repl;
- int rwright, rwleft, repl, vlines, oldcbeg, oldcend;
- char *cptr, *lptr;
-
- i = get_curtyp();
- oldcbeg = i >> 8;
- oldcend = i & 255;
- vlines = ( get_mode() == 7 ) ? 13 : 7;
- toffset = tcur = spos = count = repl = 0;
- i = ( repl ) ? vlines - 1 : 0;
- set_curtyp ( i, vlines );
- gotoxy ( col, row, page );
- vputc ( ' ', page, width );
- cptr = ptr;
- while ( *cptr++ )
- count++;
- rwleft = 0;
- rwright = 1;
- while ( 1 )
- { if ( rwleft )
- { for ( i=0, cptr = ptr + toffset; i < (width-1); i++ )
- { gotoxy ( col + i, row, page );
- vputc ( *cptr++, page, 1 );
- }
- rwleft = 0;
- }
- if ( rwright )
- { i = tcur;
- cptr = ptr + spos;
- while ( i < width )
- { gotoxy ( col + i++, row, page );
- if ( *cptr )
- { vputc ( *cptr++, page, 1 );
- }
- else
- { vputc ( ' ', page, 1 );
- break;
- }
- }
- rwright = 0;
- }
- gotoxy ( col + tcur, row, page );
- key = kbd_ci();
- if ( isprint (key) )
- goto prt_char; /* not control key */
-
- if ( key == 8 )
- { if ( spos < 1 ) /* backspace */
- goto bad_key;
- tcur--;
- spos--;
- key = DELETE;
- }
- if ( key == 7 )
- key = DELETE; /* change ^G to DELETE */
- if ( key == DELETE )
- { if ( spos >= count ) /* Delete key */
- goto bad_key;
- cptr = ptr + spos;
- lptr = cptr + 1;
- while ( *cptr )
- *cptr++ = *lptr++;
- count--;
- rwright = 1;
- }
- if ( (key == CURLF) || (key == 19) )
- { if ( spos < 1 ) /* Left arrow or ^S */
- goto bad_key;
- tcur--;
- }
- if ( (key == CURRT) || (key == 4) )
- { if ( spos >= count ) /* Right arrow or ^D */
- goto bad_key;
- tcur++;
- }
- if ( (key == 22) || (key == INSERT) )
- { repl = -1 - repl; /* Insert key or ^V */
- i = ( repl ) ? vlines - 1 : 0;
- set_curtyp ( i, vlines );
- }
- if ( key == HOME )
- tcur = -toffset; /* Home key */
- if ( key == ENDKEY )
- tcur = count - toffset; /* End Key */
- if ( key == '\r' )
- { set_curtyp ( oldcbeg, oldcend );
- return ( count ); /* Return key */
- }
- goto cur_chk;
- prt_char:
- if ( spos >= max )
- goto bad_key; /* at end of full string*/
- if ( repl && (spos < count) )
- goto repl_char; /* replace mode */
- if ( count >= max )
- goto bad_key; /* no room to insert key*/
- i = ++count - spos;
- cptr = ptr + count;
- lptr = cptr - 1;
- while ( i-- ) /* make room for key */
- *cptr-- = *lptr--;
- rwright = 1;
- repl_char:
- cptr = ptr + spos;
- *cptr = key;
- vputc ( *cptr, page, 1 );
- tcur++;
- cur_chk:
- if ( tcur < 0 )
- { toffset += tcur;
- tcur = 0;
- rwright = 1;
- }
- if ( tcur >= width )
- { toffset += tcur - width + 1;
- tcur = width - 1;
- if ( (toffset + tcur) >= max )
- toffset--;
- rwleft = 1;
- rwright = 1;
- }
- bad_key:
- spos = toffset + tcur;
- }
- }
-
- /*****************************************
- ** edit string (see ticker()) in window */
-
- int wticker(wn,ptr,max,width)
-
- WINDOWPTR wn;
- char *ptr;
- int max, width;
- {
- int i, row, col, page;
-
- row = wn->uly + wn->cy;
- col = wn->ulx + wn->cx;
- page = wn->wpage;
- i = wn->xsize - wn->cx + 1;
- if ( (i < width) && (i > 0) )
- width = i;
- return ( ticker ( row, col, ptr, max, width, page ) );
- }
-